
#include "DBN.h"

// [*] nw_rbm::CDeepBeliefNetwork

nw_rbm::CDeepBeliefNetwork::CDeepBeliefNetwork()
{
	Clear();
}

void nw_rbm::CDeepBeliefNetwork::Clear()
{
	Depth = 0;
	ListLayer.Clear();
}

void nw_rbm::CDeepBeliefNetwork::DeepClear()
{
	Depth = 0;
	ListLayer.DeepClear();
}

void nw_rbm::CDeepBeliefNetwork::InitDepth( int Depth )
{
	this->Depth = Depth;
	ListLayer.Clear();
	ListLayer.Resize(Depth);
}

nw_rbm::CRBM_with_MaxPooling& nw_rbm::CDeepBeliefNetwork::NewLayer()
{
	ListLayer.Resize(Depth+1);
	return ListLayer.pElement[Depth++];
}

nw_rbm::CRBM_with_MaxPooling& nw_rbm::CDeepBeliefNetwork::GetLayer( int LayerIndex )
{
	return ListLayer.pElement[LayerIndex];
}

void nw_rbm::CDeepBeliefNetwork::SaveWeightModelToFile( string strFN_WeightModel ) const
{
	ofstream outFile(strFN_WeightModel.c_str());
	outFile<<Depth<<endl<<endl;
	int i_layer;
	for ( i_layer = 0; i_layer < Depth; ++i_layer )
	{
		ListLayer.pElement[i_layer].SaveWeightModelToStream(outFile);
		outFile<<endl;
	}
	outFile.close();
	outFile.clear();
}

bool nw_rbm::CDeepBeliefNetwork::LoadWeightModelFromFile( string strFN_WeightModel )
{
	ifstream inFile(strFN_WeightModel.c_str());

	int i_layer;
	if (!(inFile>>i_layer)) return false;
	InitDepth(i_layer);
	for ( i_layer = 0; i_layer < Depth; ++i_layer )
	{
		if (!ListLayer.pElement[i_layer].LoadWeightModelFromStream(inFile))
			return false;
	}
	inFile.close();
	inFile.clear();
	return true;
}

void nw_rbm::CDeepBeliefNetwork::InitUnitMapping()
{
	ListMoU_BottomUp.Clear();
	ListMoU_BottomUp.Resize(Depth);
	ListMoU_TopDown.Clear();
	ListMoU_TopDown.Resize(Depth);
	int i_layer;
	for ( i_layer = 0; i_layer < Depth; ++i_layer )
	{
		CRBM_with_MaxPooling& tLayer = GetLayer(i_layer);
		CMapping_of_Units& MoU_V = ListMoU_TopDown.pElement[i_layer];
		CMapping_of_Units& MoU_P = ListMoU_BottomUp.pElement[i_layer];
		MoU_V.Resize(tLayer.AmountUnit_Visible);
		MoU_V.Fill(-1);
		MoU_P.Resize(tLayer.AmountUnit_Pooling);
		MoU_P.Fill(-1);
	}
}

void nw_rbm::CDeepBeliefNetwork::NewUnitsMapping(
	int LowerLayerIndex,
	int LowerLayerPoolingUnitIndex,
	int HigherLayerVisibleUnitIndex )
{
	if (LowerLayerIndex<0 || LowerLayerIndex+1>=Depth) return;

	CRBM_with_MaxPooling& LowerLayer = GetLayer(LowerLayerIndex);
	CRBM_with_MaxPooling& HigherLayer = GetLayer(LowerLayerIndex+1);
	if (LowerLayerPoolingUnitIndex<0 || LowerLayerPoolingUnitIndex>=LowerLayer.AmountUnit_Pooling) return;
	if (HigherLayerVisibleUnitIndex<0 || HigherLayerVisibleUnitIndex>=HigherLayer.AmountUnit_Visible) return;

	CMapping_of_Units& MoU_P = ListMoU_BottomUp.pElement[LowerLayerIndex];
	CMapping_of_Units& MoU_V = ListMoU_TopDown.pElement[LowerLayerIndex+1];
	MoU_P.pElement[LowerLayerPoolingUnitIndex] = HigherLayerVisibleUnitIndex;
	MoU_V.pElement[HigherLayerVisibleUnitIndex] = LowerLayerPoolingUnitIndex;
}

void nw_rbm::CDeepBeliefNetwork::InitWeightModel()
{
	int i_layer;
	for ( i_layer = 0; i_layer < Depth; ++i_layer )
		GetLayer(i_layer).InitWeightItems();
}

void nw_rbm::CDeepBeliefNetwork::InitWeightModel( RBM_FLOAT Variance )
{
	int i_layer;
	for ( i_layer = 0; i_layer < Depth; ++i_layer )
		GetLayer(i_layer).InitWeightItems(Variance);
}

void nw_rbm::CDeepBeliefNetwork::ClearMaxPoolingUnitsExtraEnergy(
	int BeginLayerIndex, int EndLayerIndex)
{
	if (BeginLayerIndex<0 || BeginLayerIndex>=Depth) BeginLayerIndex = 0;
	if (EndLayerIndex<0 || EndLayerIndex>=Depth) EndLayerIndex = Depth;
	int i_layer;
	for ( i_layer = BeginLayerIndex; i_layer < EndLayerIndex; ++i_layer )
		GetLayer(i_layer).ClearMaxPoolingUnitsExtraEnergy();
}

void nw_rbm::CDeepBeliefNetwork::UpdateAdjacentLayers_Energy_TopDown(
	int LowerLayerIndex )
{
	if (LowerLayerIndex<0 || LowerLayerIndex+1>=Depth) return;

	CRBM_with_MaxPooling& LowerLayer = GetLayer(LowerLayerIndex);
	CRBM_with_MaxPooling& HigherLayer = GetLayer(LowerLayerIndex+1);
	CMapping_of_Units& MoU_V = ListMoU_TopDown.pElement[LowerLayerIndex+1];

	const int* qMap = MoU_V.pElement;
	const CUnitBasic* qUV = HigherLayer.ListUnit_Visible.pElement;
	CUnitPooling* pUP = LowerLayer.ListUnit_Pooling.pElement;
	int i_V, j_P;
	for ( i_V = 0; i_V < HigherLayer.AmountUnit_Visible; ++i_V )
	{
		j_P = qMap[i_V];
		if (j_P < 0) continue;
		pUP[j_P].ExtraEnergy = qUV[i_V].Energy - 
			// Tianqi Chen
			//pUP[j_P].BiasValue;
			HigherLayer.GetUnitBiasValue_Visible(i_V);
	}
}

void nw_rbm::CDeepBeliefNetwork::UpdateAdjacentLayers_Expectation_BottomUp(
	int LowerLayerIndex )
{
	if (LowerLayerIndex<0 || LowerLayerIndex+1>=Depth) return;

	CRBM_with_MaxPooling& LowerLayer = GetLayer(LowerLayerIndex);
	CRBM_with_MaxPooling& HigherLayer = GetLayer(LowerLayerIndex+1);
	CMapping_of_Units& MoU_P = ListMoU_BottomUp.pElement[LowerLayerIndex];

	const int* qMap = MoU_P.pElement;
	const CUnitPooling* qUP = LowerLayer.ListUnit_Pooling.pElement;
	CUnitBasic* pUV = HigherLayer.ListUnit_Visible.pElement;
	int i_P;
	for ( i_P = 0; i_P < LowerLayer.AmountUnit_Pooling; ++i_P )
	{
		if (qMap[i_P] < 0) continue;
		pUV[qMap[i_P]].Expectation = qUP[i_P].Expectation;
	}
}

//void nw_rbm::CDeepBeliefNetwork::UpdateAdjacentLayers_Expectation_TopDown( int LowerLayerIndex )
//{
//	if (LowerLayerIndex<0 || LowerLayerIndex+1>=Depth) return;
//
//	CRBM_with_MaxPooling& LowerLayer = GetLayer(LowerLayerIndex);
//	CRBM_with_MaxPooling& HigherLayer = GetLayer(LowerLayerIndex+1);
//	CMapping_of_Units& MoU_V = ListMoU_TopDown.pElement[LowerLayerIndex+1];
//
//	//LowerLayer.ComputeBiasOnlyExpectation_of_Units_Hidden();
//
//	const int* qMap = MoU_V.pElement;
//	const CUnitBasic* qUV = HigherLayer.ListUnit_Visible.pElement;
//	CUnitPooling* pUP = LowerLayer.ListUnit_Pooling.pElement;
//	int i_V, j_P;
//	for ( i_V = 0; i_V < HigherLayer.AmountUnit_Visible; ++i_V )
//	{
//		j_P = qMap[i_V];
//		if (j_P < 0) continue;
//		pUP[j_P].Expectation = qUV[i_V].Expectation;
//	}
//}

void nw_rbm::CDeepBeliefNetwork::UpdateAdjacentLayers_State_BottomUp( int LowerLayerIndex )
{
	if (LowerLayerIndex<0 || LowerLayerIndex+1>=Depth) return;

	CRBM_with_MaxPooling& LowerLayer = GetLayer(LowerLayerIndex);
	CRBM_with_MaxPooling& HigherLayer = GetLayer(LowerLayerIndex+1);
	CMapping_of_Units& MoU_P = ListMoU_BottomUp.pElement[LowerLayerIndex];

	const int* qMap = MoU_P.pElement;
	const CUnitPooling* qUP = LowerLayer.ListUnit_Pooling.pElement;
	CUnitBasic* pUV = HigherLayer.ListUnit_Visible.pElement;
	int i_P;
	for ( i_P = 0; i_P < LowerLayer.AmountUnit_Pooling; ++i_P )
	{
		if (qMap[i_P] < 0) continue;
		pUV[qMap[i_P]].State = (qUP[i_P].State<0 ? 1.0f : 0.0f);
	}
}

void nw_rbm::CDeepBeliefNetwork::UpdateAdjacentLayers_State_TopDown( int LowerLayerIndex )
{
	if (LowerLayerIndex<0 || LowerLayerIndex+1>=Depth) return;

	CRBM_with_MaxPooling& LowerLayer = GetLayer(LowerLayerIndex);
	CRBM_with_MaxPooling& HigherLayer = GetLayer(LowerLayerIndex+1);
	CMapping_of_Units& MoU_V = ListMoU_TopDown.pElement[LowerLayerIndex+1];

	const int* qMap = MoU_V.pElement;
	const CUnitBasic* qUV = HigherLayer.ListUnit_Visible.pElement;
	CUnitPooling* pUP = LowerLayer.ListUnit_Pooling.pElement;
	int i_V;
	for ( i_V = 0; i_V < HigherLayer.AmountUnit_Visible; ++i_V )
	{
		if (qMap[i_V] < 0) continue;
		pUP[qMap[i_V]].State = (
			(CMyRandom::NextDouble()<qUV[i_V].State)
			? 0 : -1);
	}

	LowerLayer.SampleState_of_Units_Hidden_GivenPoolingState();
}

void nw_rbm::CDeepBeliefNetwork::Make_RBM_InferenceHelper(
	int LayerIndex,
	C_RBM_InferenceHelper*& p_RBM_InferenceHelper)
{
	if (LayerIndex<0 || LayerIndex>=Depth) return;

	p_RBM_InferenceHelper = new C_RBM_InferenceHelper;
	//TODO
	return;
}

void nw_rbm::CDeepBeliefNetwork::ClearTrainingInfo( int LayerIndex )
{
	if (LayerIndex<0 || LayerIndex>=Depth) return;
	CRBM_with_MaxPooling& tLM = GetLayer(LayerIndex);
	tLM.ClearTrainingInfo();
}

void nw_rbm::CDeepBeliefNetwork::ComputeBothGradient(
	int LayerIndex,
	RBM_FLOAT SpaCod_SparseLevel,
	RBM_FLOAT ExampleWeight, RBM_FLOAT GradientAmendment )
{
	if (LayerIndex<0 || LayerIndex>=Depth) return;
	CRBM_with_MaxPooling& tLM = GetLayer(LayerIndex);

	if (1)
	{
		C_RBM_InferenceHelper* p_RBM_InferenceHelper;
		this->Make_RBM_InferenceHelper(
			LayerIndex,
			p_RBM_InferenceHelper);
		tLM.ComputeBothGradient(
			p_RBM_InferenceHelper,
			SpaCod_SparseLevel,
			ExampleWeight, GradientAmendment,
			1);
		CDataStructureTools::MyRelease_Single(p_RBM_InferenceHelper);
	}
}

void nw_rbm::CDeepBeliefNetwork::UpdateBothGradient(
	int LayerIndex,
	RBM_FLOAT LearningRate, RBM_FLOAT SpaCod_Lambda,
	RBM_FLOAT ConDiv_Decay_Mask, RBM_FLOAT ConDiv_Decay_Bias, RBM_FLOAT ConDiv_Momentum)
{
	if (LayerIndex<0 || LayerIndex>=Depth) return;
	CRBM_with_MaxPooling& tLM = GetLayer(LayerIndex);
	tLM.UpdateBothGradient(
		LearningRate, SpaCod_Lambda,
		ConDiv_Decay_Mask, ConDiv_Decay_Bias, ConDiv_Momentum);
}

RBM_FLOAT nw_rbm::CDeepBeliefNetwork::GetCumulativeCosts(
	int LayerIndex, 
	RBM_FLOAT SpaCod_Lambda,
	RBM_FLOAT& VisibleError, RBM_FLOAT& HiddenPenalty )
{
	if (LayerIndex<0 || LayerIndex>=Depth) return 0.0f;
	CRBM_with_MaxPooling& tLM = GetLayer(LayerIndex);
	VisibleError = tLM.GetCumulativeVisibleError();
	HiddenPenalty = tLM.GetCumulativeHiddenPenalty();
	RBM_FLOAT ret = VisibleError + SpaCod_Lambda * HiddenPenalty;
	return ret;
}

void nw_rbm::CDeepBeliefNetwork::PrepareTrainingLayer( int LayerIndex )
{
	if (LayerIndex<0 || LayerIndex>=Depth) return;

	CRBM_with_MaxPooling& tLM = GetLayer(LayerIndex);
	int i;

	for ( i = 0; i < tLM.AmountWeightItem_Visible; ++i )
		tLM.ListWeightItem_Visible.pElement[i].fValueFixed = false;
	for ( i = 0; i < tLM.AmountWeightItem_Hidden; ++i )
		tLM.ListWeightItem_Hidden.pElement[i].fValueFixed = false;
	for ( i = 0; i < tLM.AmountWeightItem_Edge; ++i )
		tLM.ListWeightItem_Edge.pElement[i].fValueFixed = false;

	if (LayerIndex > 0)
	{
		FinishTrainingLayer(LayerIndex - 1);

		CRBM_with_MaxPooling& qLM = GetLayer(LayerIndex-1);
		CMapping_of_Units& MoU_V = ListMoU_TopDown.pElement[LayerIndex];
		const int* qMap = MoU_V.pElement;
		CUnitBasic* pUV = tLM.ListUnit_Visible.pElement;
		const CUnitPooling* qUP = qLM.ListUnit_Pooling.pElement;
		int i_V, j_P;
		for ( i_V = 0; i_V < tLM.AmountUnit_Visible; ++i_V )
		{
			j_P = qMap[i_V];
			if (j_P < 0) continue;
			if (pUV[i_V].BiasIndex < 0) continue;
			CWeightItem& tWI = tLM.ListWeightItem_Visible.pElement[pUV[i_V].BiasIndex];
			if (!tWI.fValueFixed)
			{
				tWI.ClearAll();
				tWI.fValueFixed = true;
			}
			tWI.Value += qUP[j_P].BiasValue;
			tWI.ConDiv_CumulativeWeight += 1.0f;
		}
		for ( i = 0; i < tLM.AmountWeightItem_Visible; ++i )
		{
			CWeightItem& tWI = tLM.ListWeightItem_Visible.pElement[i];
			if (!tWI.fValueFixed) continue;
			tWI.Value /= tWI.ConDiv_CumulativeWeight;
			//tWI.ConDiv_CumulativeWeight = tWI.Value - log(4.0);
			tWI.ConDiv_CumulativeWeight = 0.0f;
		}
	} // (LayerIndex > 0)
}

void nw_rbm::CDeepBeliefNetwork::FinishTrainingLayer( int LayerIndex )
{
	if (LayerIndex<0 || LayerIndex>=Depth) return;

	CRBM_with_MaxPooling& tLM = GetLayer(LayerIndex);

	tLM.UpdateUnitsBiasValue_Pooling();
}

void nw_rbm::CDeepBeliefNetwork::InferenceLevelUnit(
	int LevelIndex,
	bool fBottomUp, bool fTopDown,
	bool fUseMeanField )
{
	if (LevelIndex<0 || LevelIndex>Depth || Depth<1) return;
	CRBM_with_MaxPooling* pLowerLayer = ListLayer.pElement + LevelIndex - 1;
	CRBM_with_MaxPooling* pHigherLayer = ListLayer.pElement + LevelIndex;
	if (LevelIndex==0)
	{
		pLowerLayer = NULL;
		fBottomUp = false;
	}
	if (LevelIndex==Depth)
	{
		pHigherLayer = NULL;
		fTopDown = false;
	}

	C_RBM_InferenceHelper* pInferenceHelper;

	if (fTopDown)
	{ // fTopDown
		this->Make_RBM_InferenceHelper(LevelIndex, pInferenceHelper);
		pHigherLayer->InferenceEnergy_of_Units_Visible(pInferenceHelper);
		CDataStructureTools::MyRelease_Single(pInferenceHelper);

		UpdateAdjacentLayers_Energy_TopDown(LevelIndex-1);
	} // fTopDown
	else
	{ // !fTopDown
		if (pLowerLayer != NULL)
			pLowerLayer->ClearMaxPoolingUnitsExtraEnergy();
	} // !fTopDown

	if (fBottomUp)
	{ // fBottomUp
		this->Make_RBM_InferenceHelper(LevelIndex-1, pInferenceHelper);
		pLowerLayer->InferenceEnergy_of_Units_Hidden(pInferenceHelper);
		CDataStructureTools::MyRelease_Single(pInferenceHelper);

		pLowerLayer->ComputeExpectation_of_Units_Hidden();
		UpdateAdjacentLayers_Expectation_BottomUp(LevelIndex-1);

		if (fUseMeanField)
		{ // fUseMeanField
			pLowerLayer->CopyUnitsExpectationToState_Hidden();
			if (pHigherLayer != NULL)
				pHigherLayer->CopyUnitsExpectationToState_Visible();
		} // fUseMeanField
		else
		{ // !fUseMeanField
			pLowerLayer->SampleState_of_Units_Hidden();
			UpdateAdjacentLayers_State_BottomUp(LevelIndex-1);
		} // !fUseMeanField
	} // fBottomUp
	else if (pHigherLayer!=NULL)
	{ // !fBottomUp && pHigherLayer!=NULL
		if (!fTopDown)
			pHigherLayer->SetBiasOnlyEnergy_of_Units_Visible();

		if (pLowerLayer==NULL)
			pHigherLayer->ComputeExpectation_of_Units_Visible();
		else
		{
			pLowerLayer->ComputeBiasOnlyExpectation_of_Units_Hidden();
			UpdateAdjacentLayers_Expectation_BottomUp(LevelIndex-1);
		}

		if (fUseMeanField)
		{ // fUseMeanField
			pHigherLayer->CopyUnitsExpectationToState_Visible();
			if (pLowerLayer != NULL)
				pLowerLayer->CopyUnitsExpectationToState_Hidden();
		} // fUseMeanField
		else
		{ // !fUseMeanField
			pHigherLayer->SampleState_of_Units_Visible();
			UpdateAdjacentLayers_State_TopDown(LevelIndex-1);
		} // !fUseMeanField
	} // !fBottomUp && pHigherLayer!=NULL
	else
	{ // !fBottomUp && pHigherLayer==NULL
		pLowerLayer->SetBiasOnlyEnergy_of_Units_Hidden();

		if (fUseMeanField)
		{ // fUseMeanField
			pLowerLayer->CopyUnitsExpectationToState_Hidden();
		} // fUseMeanField
		else
		{ // !fUseMeanField
			pLowerLayer->SampleState_of_Units_Hidden();
		} // !fUseMeanField
	} // !fBottomUp && pHigherLayer==NULL
}

void nw_rbm::CDeepBeliefNetwork::InferenceSubNetwork(
	int BeginLevelIndex, int EndLevelIndex,
	bool fFixInitialState,
	bool fUseMeanField,
	int AmountInteration )
{
	if (BeginLevelIndex < 0) BeginLevelIndex = 0;
	if (EndLevelIndex > Depth) EndLevelIndex = Depth;

	int i, j;
	for ( i = 0; i < AmountInteration; ++i )
	{
		j = BeginLevelIndex;
		if (i==0 || fFixInitialState) ++j;
		for ( ; j <= EndLevelIndex; ++j )
		{
			InferenceLevelUnit(
				j, (j>BeginLevelIndex), (i>0 && j<EndLevelIndex), fUseMeanField);
		} // j
	} // i
}

void nw_rbm::CDeepBeliefNetwork::InferenceOnce_SingleLayer_BottomUp(
	int LayerIndex,
	bool fAcceptEnergyFromHigherLayer,
	bool fPassExpectationUp )
{
	if (LayerIndex<0 || LayerIndex>=Depth) return;

	CRBM_with_MaxPooling& CurrentLayer = GetLayer(LayerIndex);

	if (1)
	{
		C_RBM_InferenceHelper* p_RBM_InferenceHelper;
		this->Make_RBM_InferenceHelper(LayerIndex, p_RBM_InferenceHelper);
		CurrentLayer.InferenceEnergy_of_Units_Hidden(p_RBM_InferenceHelper);
		CDataStructureTools::MyRelease_Single(p_RBM_InferenceHelper);
	}

	if (!fAcceptEnergyFromHigherLayer)
		CurrentLayer.ClearMaxPoolingUnitsExtraEnergy();
	CurrentLayer.ComputeExpectation_of_Units_Hidden();

	if (fPassExpectationUp)
	{
		CurrentLayer.CopyUnitsExpectationToState_Hidden();
		UpdateAdjacentLayers_Expectation_BottomUp(LayerIndex);
		if (LayerIndex+1 < Depth)
			GetLayer(LayerIndex+1).CopyUnitsExpectationToState_Visible();
	}
	else
	{
		CurrentLayer.SampleState_of_Units_Hidden();
		UpdateAdjacentLayers_State_BottomUp(LayerIndex);
	}
}

void nw_rbm::CDeepBeliefNetwork::InferenceOnce_SingleLayer_TopDown(
	int LayerIndex,
	bool fPassExpectationDown )
{
	if (LayerIndex<0 || LayerIndex>=Depth) return;

	CRBM_with_MaxPooling& CurrentLayer = GetLayer(LayerIndex);

	if (1)
	{
		C_RBM_InferenceHelper* p_RBM_InferenceHelper;
		this->Make_RBM_InferenceHelper(LayerIndex, p_RBM_InferenceHelper);
		CurrentLayer.InferenceEnergy_of_Units_Visible(p_RBM_InferenceHelper);
		CDataStructureTools::MyRelease_Single(p_RBM_InferenceHelper);
	}

	CurrentLayer.ComputeExpectation_of_Units_Visible();

	if (fPassExpectationDown)
	{
		CurrentLayer.CopyUnitsExpectationToState_Visible();
		if (LayerIndex-1 >= 0)
		{
			UpdateAdjacentLayers_Energy_TopDown(LayerIndex-1);
			GetLayer(LayerIndex-1).ComputeExpectation_of_Units_Hidden();
		}
	}
	else
	{
		CurrentLayer.SampleState_of_Units_Visible();
		UpdateAdjacentLayers_State_TopDown(LayerIndex-1);
	}
}

void nw_rbm::CDeepBeliefNetwork::InferenceOnce_SubNetwork_BottomUp(
	int BeginLayerIndex, int EndLayerIndex,
	bool fAcceptEnergyFromHigherLayer,
	bool fPassExpectationUp )
{
	if (BeginLayerIndex<0 || BeginLayerIndex>=Depth) BeginLayerIndex = 0;
	if (EndLayerIndex<0 || EndLayerIndex>=Depth) EndLayerIndex = Depth;
	int i_layer;
	for ( i_layer = BeginLayerIndex; i_layer < EndLayerIndex; ++i_layer )
	{
		InferenceOnce_SingleLayer_BottomUp(i_layer, fAcceptEnergyFromHigherLayer, fPassExpectationUp);
	}
}

void nw_rbm::CDeepBeliefNetwork::InferenceOnce_SubNetwork_TopDown(
	int BeginLayerIndex, int EndLayerIndex,
	bool fPassExpectationUp )
{
	if (BeginLayerIndex<0 || BeginLayerIndex>=Depth) BeginLayerIndex = Depth;
	if (EndLayerIndex<0 || EndLayerIndex>=Depth) EndLayerIndex = 0;
	int i_layer;
	for ( i_layer = BeginLayerIndex - 1; i_layer >= EndLayerIndex; --i_layer )
		InferenceOnce_SingleLayer_TopDown(i_layer, fPassExpectationUp);
}

void nw_rbm::CDeepBeliefNetwork::InferenceTimes_SubNetwork_BottomUp(
	int BeginLayerIndex, int EndLayerIndex,
	int AmountIteration,
	bool fPassExpectationUp )
{
	int i_iteration;
	ClearMaxPoolingUnitsExtraEnergy(BeginLayerIndex, EndLayerIndex);
	for ( i_iteration = 0; i_iteration < AmountIteration; ++i_iteration )
	{
		InferenceOnce_SubNetwork_BottomUp(
			BeginLayerIndex, EndLayerIndex, true, fPassExpectationUp);
	}
}

void nw_rbm::CDeepBeliefNetwork::InferenceTimes_SubNetwork_TopDown(
	int BeginLayerIndex, int EndLayerIndex,
	int AmountIteration,
	bool fPassExpectationUp )
{
	int i_iteration;
	for ( i_iteration = 0; i_iteration < AmountIteration; ++i_iteration )
	{
		InferenceOnce_SubNetwork_TopDown(
			BeginLayerIndex, EndLayerIndex, fPassExpectationUp);
	}
}

void nw_rbm::CDeepBeliefNetwork::FullInference_BottomUp(
	int AmountIteration,
	bool fPassExpectationUp )
{
	InferenceTimes_SubNetwork_BottomUp(
		0, Depth, AmountIteration, fPassExpectationUp);
}

void nw_rbm::CDeepBeliefNetwork::FullInference_TopDown(
	int AmountIteration,
	bool fPassExpectationUp )
{
	InferenceTimes_SubNetwork_TopDown(
		Depth, 0, AmountIteration, fPassExpectationUp);
}

